package com.joymart.aftersale.service;

import com.joymart.aftersale.model.AfterSaleSheet;
import com.joymart.common.model.ApprovalStatus;
import com.joymart.common.model.Range;
import com.joymart.common.utils.SecurityUtils;
import com.joymart.order.model.Order;
import com.joymart.order.service.OrderService;
import com.joymart.product.model.Product;
import com.joymart.product.service.ProductService;
import com.joymart.user.model.User;
import com.joymart.user.repo.UserRepository;
import com.joymart.user.service.UserCacheManager;
import jakarta.annotation.PostConstruct;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Id;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.MathContext;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static com.joymart.common.utils.CollectionUtils.asList;
import static org.springframework.data.relational.core.query.Criteria.where;
import static org.springframework.data.relational.core.query.Query.query;

@Service
public class AfterSaleQueryService {

    @Autowired
    public AfterSaleService afterSaleService;
    @Autowired
    private ProductService productService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private UserCacheManager userCacheManager;
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private JdbcAggregateTemplate jdbcAggregateTemplate;
    @PostConstruct
    public void init() {
        headQuarter = userRepository.findById("10000").get();
    }

    private User headQuarter;

    public Page<?> searchShopAfterSales(Range range, Pageable pageable, String orderId, ApprovalStatus approvalStatus) {
        Criteria criteria =  where("createdAt").between(range.getStart(), range.getEnd())
                .and("firstSellerId").is(SecurityUtils.getCurrentUserId());
         if(approvalStatus!=null){
            criteria=criteria.and("status").is(approvalStatus);
         }
        if(StringUtils.hasText(orderId)){
            criteria=criteria.and("orderId").is(orderId);
        }

        long count = jdbcAggregateTemplate.count(query(criteria), AfterSaleSheet.class);
        if(count == 0){
            return Page.empty();
        }else {
            List<AfterSaleSheet> content = asList(jdbcAggregateTemplate
                    .findAll(query(criteria).limit(pageable.getPageSize()).offset(pageable.getOffset())
                            .sort(Sort.by(Sort.Direction.DESC, "createdAt")), AfterSaleSheet.class));
            return new PageImpl<>(content,pageable , count).map(this::toDto);
        }
    }

    public Page<?> searchCustomerAfterSales(Range range, Pageable pageable, String orderId, ApprovalStatus approvalStatus) {
        Criteria criteria =
                where("buyerId").is(SecurityContextHolder.getContext().getAuthentication().getPrincipal())
                        .and(where("createdAt").between(range.getStart(), range.getEnd()));
        if(approvalStatus!=null){
            criteria=criteria.and("status").is(approvalStatus);
        }
        if(StringUtils.hasText(orderId)){
            criteria=criteria.and("orderId").is(orderId);
        }

        long count = jdbcAggregateTemplate.count(query(criteria), AfterSaleSheet.class);
        if(count == 0){
            return Page.empty();
        }else {
            List<AfterSaleSheet> content = asList(jdbcAggregateTemplate
                    .findAll(query(criteria).limit(pageable.getPageSize()).offset(pageable.getOffset())
                            .sort(Sort.by(Sort.Direction.DESC, "createdAt")), AfterSaleSheet.class));
            return new PageImpl<>(content,pageable , count).map(this::toDto);
        }
    }

    public Page<?> searchWaitingAfterSales(Range range, Pageable pageable) {
        Criteria criteria =
                where("secondSellerId").is(SecurityUtils.getCurrentUserId())
                        .and("status").is(ApprovalStatus.APPROVED)
                        .and("secondSellerRefunded").isFalse()
                        .and(where("createdAt").between(range.getStart(), range.getEnd()));
        long count = jdbcAggregateTemplate.count(query(criteria), AfterSaleSheet.class);
        if(count == 0){
            return Page.empty();
        }else {
            List<AfterSaleSheet> content = asList(jdbcAggregateTemplate
                    .findAll(query(criteria).limit(pageable.getPageSize()).offset(pageable.getOffset())
                            .sort(Sort.by(Sort.Direction.DESC, "createdAt")), AfterSaleSheet.class));
            return new PageImpl<>(content,pageable , count).map(this::toDto);
        }
    }

    public Page<?> searchAdminAfterSales(Range range, Pageable pageable, ApprovalStatus approvalStatus, String orderId, boolean waitingOnly) {
        Criteria criteria = where("createdAt").between(range.getStart(), range.getEnd());
        if(waitingOnly){
            criteria = criteria.and("status").is(ApprovalStatus.APPROVED).and("headQuarterRefunded").isFalse();
        }else if(approvalStatus!=null){
            criteria = criteria.and("status").is(approvalStatus);
        }
        if(StringUtils.hasText(orderId)){
            criteria = criteria.and("orderId").is(orderId);
        }

        long count = jdbcAggregateTemplate.count(query(criteria), AfterSaleSheet.class);
        if(count == 0){
            return Page.empty();
        }else {
            List<AfterSaleSheet> content = asList(jdbcAggregateTemplate
                    .findAll(query(criteria).limit(pageable.getPageSize()).offset(pageable.getOffset())
                            .sort(Sort.by(Sort.Direction.DESC, "createdAt")), AfterSaleSheet.class));
            return new PageImpl<>(content,pageable , count).map(this::toDto);
        }
    }
    public AfterSaleSheetDto toDto(AfterSaleSheet source){
        AfterSaleSheetDto dto = new AfterSaleSheetDto();

        BeanUtils.copyProperties(source,dto);
        dto.setBuyer(userCacheManager.get(source.getBuyerId()).getUser());
        dto.setFirstSeller(userCacheManager.get(source.getFirstSellerId()).getUser());
        dto.setSecondSeller(userCacheManager.get(source.getSecondSellerId()).getUser());
        dto.setOrder(orderService.getById(source.getOrderId()));
        dto.setHeadQuarter(this.headQuarter);
        dto.setProduct(productService.findByIdFromCache(dto.getOrder().getProductId()));
        dto.setActions(new ArrayList<>());
        dto.setInstructions(new ArrayList<>());
        if(source.getStatus() == ApprovalStatus.PENDING){
            if(SecurityUtils.getCurrentUserId().equals(source.getFirstSellerId())){
                dto.getActions().addAll(List.of("APPROVE","REJECT"));
            }
            return dto;
        }

        if(source.getStatus() == ApprovalStatus.REJECTED){
            return dto;
        }

        //source.getStatus() == ApprovalStatus.APPROVED
        if(source.getBuyerId().equals(SecurityUtils.getCurrentUserId()) //只是买家
            && !source.getFirstSellerId().equals(SecurityUtils.getCurrentUserId())
            && !source.getSecondSellerId().equals(SecurityUtils.getCurrentUserId())
            && source.isFirstSellerRefunded()==false){
            dto.getInstructions().add(
                    new Instruction("请联系店铺退款，并根据店铺提供的地址退还商品", dto.getFirstSeller(), null));
        }

        if(source.getFirstSellerId().equals(SecurityUtils.getCurrentUserId())){ // 经营店铺
            if(dto.isHeadQuarterRefunded() ==false){
                dto.getInstructions().add(
                        new Instruction("总部尚未收到退货，请退还商品。总部确认后将进行退款", dto.getHeadQuarter(), null));
            }

            if(dto.isFirstSellerRefunded()==false && !source.getBuyerId().equals(SecurityUtils.getCurrentUserId())) {
                dto.getInstructions().add(
                        new Instruction("请向买家提供退货地址，并将订单金额[%s]元全额返还给买家, 退款后点击确认".formatted(dto.getOrder().getTotalPrice()),
                                dto.getBuyer(), "CONFIRM_FIRST_SELLER_REFUNDED"));
            }

            if(dto.isFirstSellerRefunded()==false && source.getBuyerId().equals(SecurityUtils.getCurrentUserId())) {
                dto.getInstructions().add(
                        new Instruction("由于是自购商品, 您可以直接确认店铺已退款".formatted(dto.getOrder().getTotalPrice()),
                                null, "CONFIRM_FIRST_SELLER_REFUNDED"));
            }

            if(dto.isSecondSellerRefunded()==false && !source.getSecondSellerId().equals(SecurityUtils.getCurrentUserId())){
                dto.getInstructions().add(
                        new Instruction("请联系管理店铺要求其退还育成利润[%s]元，退还后请点击确认".formatted(dto.getOrder().getSecondSellerProfit()),
                                dto.getSecondSeller(),"CONFIRM_SECOND_SELLER_REFUNDED"));
            }

            if(dto.isSecondSellerRefunded()==false && source.getSecondSellerId().equals(SecurityUtils.getCurrentUserId())){
                dto.getInstructions().add(
                        new Instruction("由于您即是管理店铺又是经营店铺，您可以直接确认管理店铺已退还育成利润", null,"CONFIRM_SECOND_SELLER_REFUNDED"));
            }

        }

        if(source.getSecondSellerId().equals(SecurityUtils.getCurrentUserId())){ // 管理店铺
            if(dto.isSecondSellerRefunded() ==false && !dto.getFirstSeller().equals(SecurityUtils.getCurrentUserId())){
                dto.getInstructions().add(new Instruction("此售后申请已经通过，请向下级店铺返还育成利润[%s]元".formatted(dto.getOrder().getSecondSellerProfit()), dto.getFirstSeller(),null));
            }
        }

        return dto;
    }




    @Data
    public static class AfterSaleSheetDto {
        @Id
        private String id;
        private Order order;
        private Product product;
        private ApprovalStatus status;
        private String imageUrl0;
        private String imageUrl1;
        private String imageUrl2;
        private String imageUrl3;
        private String imageUrl4;
        private String imageUrl5;

        private User headQuarter;
        private User buyer;
        private User firstSeller;
        private User secondSeller;

        // 经营店铺已退款给买家
        private boolean firstSellerRefunded;
        // 管理店铺已退款给经营店铺
        private boolean secondSellerRefunded;
        // 总部收到退货并退款给经营店铺
        private boolean headQuarterRefunded;
        private String remarkBySeller;
        private String remarkByBuyer;
        private LocalDateTime createdAt;

        private List<String> actions;
        private List<Instruction> instructions;

        public BigDecimal getHeadQuarterRefundAmount() {
           Order order = this.getOrder();
           return order.getTotalPrice()
                   .subtract(order.getFirstSellerProfit(),MathContext.DECIMAL64)
                   .subtract(order.getSecondSellerProfit(),MathContext.DECIMAL64);
        }

        public boolean isComplete(){
            return this.isSecondSellerRefunded()
                    && this.isFirstSellerRefunded()
                    && this.isHeadQuarterRefunded();
        }

    }

    @Data
    @AllArgsConstructor
    private static class Instruction{
        private String content;
        private User instructionUser;
        private String extraAction;
    }

}
